<template>
  <div class="container">
    <div class="control">
      <el-button type="success" @click="animation1">↻</el-button>
      <el-button type="success" @click="animation2">↺</el-button>
      <el-button type="success" @click="animation3">沈阳</el-button>
      <el-button type="success" @click="animation4">北京</el-button>
      <el-button type="success" @click="animation5">上海</el-button>
      <el-button type="success" @click="animation6">武汉</el-button>
      <el-button type="success" @click="animation7">广州</el-button>
      <el-button type="success" @click="animation8">海口</el-button>
      <el-button type="success" @click="animation9">旅行</el-button>
    </div>
    <div id="map-container"></div>
  </div>
</template>
<script setup lang='ts'>
import { onMounted } from 'vue';
import 'ol/ol.css'
import { Map, View } from 'ol'
import { useTianTileLayer, projection } from '@/hooks'
import { TiandiTileLayerConfigEnum } from '@/enum'
import { easeIn, easeOut } from 'ol/easing.js'

let map: Map, view: View

onMounted(() => {
  initMap()
})

const shenyang = [123.24, 41.50]
const beijing = [116.28, 39.54]
const shanghai = [121.29, 31.14]
const wuhan = [114.21, 30.37]
const guangzhou = [113.15, 23.08]
const haikou = [110.20, 20.02]

// 初始化地图
function initMap() {
  view = new View({
    center: [116.413467,39.914935],
    projection: projection,
    zoom: 10,
    maxZoom: 17,
    minZoom: 1
  })
  map = new Map({
    target: 'map-container',
    layers: [ ...useTianTileLayer(TiandiTileLayerConfigEnum.SL) ],
    view: view
  })
}

const animation1 = () => {
  view.animate({
    rotation: view.getRotation() + Math.PI / 2,
  })
}

const animation2 = () => {
  view.animate({
    rotation: view.getRotation() - Math.PI / 2,
  })
}

const animation3 = () => {
  view.animate({
    center: shenyang,
    duration: 2000,
  });
}

const animation4 = () => {
  view.animate({
    center: beijing,
    duration: 2000,
    easing: elastic,
  });
}

const animation5 = () => {
  view.animate({
    center: shanghai,
    duration: 2000,
    easing: bounce,
  });
}

const animation6 = () => {
  const center = view.getCenter()!;
  view.animate(
    {
      center: [
        center[0] + (wuhan[0] - center[0]) / 2,
        center[1] + (wuhan[1] - center[1]) / 2,
      ],
      rotation: Math.PI,
      easing: easeIn,
    },
    {
      center: wuhan,
      rotation: 2 * Math.PI,
      easing: easeOut,
    }
  );
}

const animation7 = () => {
  flyTo(guangzhou, function () {});
}

const animation8 = () => {
  const rotation = view.getRotation();
  view.animate(
    {
      rotation: rotation + Math.PI,
      anchor: haikou,
      easing: easeIn,
    },
    {
      rotation: rotation + 2 * Math.PI,
      anchor: haikou,
      easing: easeOut,
    }
  );
}

const animation9 = () => {
  tour()
}

const tour = () =>  {
  const locations = [shenyang, beijing, shanghai, wuhan, guangzhou, haikou];
  let index = -1;
  function next(more: boolean) {
    if (more) {
      ++index;
      if (index < locations.length) {
        const delay = index === 0 ? 0 : 750;
        setTimeout(function () {
          flyTo(locations[index], next);
        }, delay);
      } else {
        alert('Tour complete');
      }
    } else {
      alert('Tour cancelled');
    }
  }
  next(true);
}

function elastic(t: number) {
  return (
    Math.pow(2, -10 * t) * Math.sin(((t - 0.075) * (2 * Math.PI)) / 0.3) + 1
  );
}

function bounce(t: number) {
  const s = 7.5625;
  const p = 2.75;
  let l;
  if (t < 1 / p) {
    l = s * t * t;
  } else {
    if (t < 2 / p) {
      t -= 1.5 / p;
      l = s * t * t + 0.75;
    } else {
      if (t < 2.5 / p) {
        t -= 2.25 / p;
        l = s * t * t + 0.9375;
      } else {
        t -= 2.625 / p;
        l = s * t * t + 0.984375;
      }
    }
  }
  return l;
}

function flyTo(location: Array<number>, done: (params?: any) => void) {
  const duration = 2000;
  const zoom = view.getZoom()!;
  let parts = 2;
  let called = false;
  function callback(complete: any) {
    --parts;
    if (called) {
      return;
    }
    if (parts === 0 || !complete) {
      called = true;
      done(complete);
    }
  }
  view.animate(
    {
      center: location,
      duration: duration,
    },
    callback
  );
  view.animate(
    {
      zoom: zoom - 1,
      duration: duration / 2,
    },
    {
      zoom: zoom,
      duration: duration / 2,
    },
    callback
  );
}
</script>
<style scoped>
.container {
  width: 100%;
  height: 100%;
}
.container .control {
  width: 100%;
  height: 35px;
  display: flex;
  justify-content: center;
}
#map-container {
  width: 100%;
  height: calc(100% - 35px);
  position: relative;
}
</style>